<template>
  <div>
    <div class="chart-icon" id="chart-icon" @click="showCall">
      <svg-icon icon-class="wechat" class="icon" id="wechat-icon" style="pointer-events: none" />
      <div class="unRead" v-if="!show && unreadCount > 0" id="read-icon">
        {{ unreadCount }}
      </div>
    </div>
    <div class="chart-container" v-show="show">
      <div class="c-title">
        <div>在线聊天</div>
        <div style="cursor: pointer;" @click="close"><i class="el-icon-close"></i></div>
      </div>
      <!-- 主内容 -->
      <div class="cont">
        <!-- 左边好友区域 -->
        <div class="friend-cont">
          <div class="f-title">
            <span>联系人</span>
            <div class="f-icons" @click="showSearch">
              <svg-icon icon-class="search" class="icon" />
              <input ref="friendSearchInput" class="useSearch" v-if="canSearch" v-model="frinedSearchKey"
                @input="filterFrineds" @blur="searchBlur" />
            </div>
            <!-- 搜索内容区域 -->
            <div :class="['search-result-box', 'chat-scroll']" v-if="canSearch">
              <!-- <div style="color: #999">查找联系人</div> -->
              <div class="sr-list">
                <div class="sr-item" v-for="item in userList" :key="item.id" @click="chooseToTalk(item)"
                  @mouseenter="mouseSelect = true" @mouseleave="mouseSelect = false">
                  <img :src="item.avatar ? item.avatar : defaultAvatar" class="usr-logo" />
                  <div class="usr-info">
                    <div class="usr-name">
                      <div style="text-overflow: ellipsis;"> {{ item.name }}</div>
                      <div class="usr-dept" v-if="item.depts.length > 0">
                        <el-tag size="mini"> {{ item.depts[0].name }}</el-tag>
                      </div>
                    </div>
                    <div class="usr-dept" v-if="item.posts.length > 0">
                      <span size="mini">{{ item.posts[0].name }}</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <!-- 好友列表 -->
          <div :class="['f-list', 'chat-scroll']">
            <div :class="[
              'f-item',
              item.id == checkFriend.id ? 'f-item-checked' : '',
            ]" v-for="item in friends" :key="item.id" @click="changeFrind(item)">
              <div class="f-logo">
                <img :src="item.avatar ? item.avatar : defaultAvatar" />
                <svg-icon :icon-class="item.isOnline == 1 ? 'isLine' : 'offLine'"
                  :class="['online-staus', item.isOnline == 1 ? 'on' : 'off']" />
              </div>
              <div class="info">
                <div class="name">{{ item.receiverName }}</div>
                <div class="text">{{ item.lastMessage }}</div>
              </div>
              <div class="type">
                <div>
                  <div class="num" v-if="item.unread > 0">
                    {{ item.unread }}
                  </div>
                </div>
                <span>{{ item.lastMessageTime }}</span>
              </div>
            </div>
          </div>
        </div>
        <!-- 右边聊天区域 -->
        <div class="chat-rest">
          <!-- 头部好友名称及状态信息 -->
          <div class="mes-status">
            <div class="mes-status-child" v-if="checkFriend && messages.length > 0">
              <div class="name">{{ checkFriend.receiverName }}</div>
              <div class="line" v-if="checkFriend.isOnline == 1"></div>
              <div class="offline" v-if="checkFriend.isOnline != 1">离线</div>
              <OptionBtn :user="checkFriend" :list="allUserList"></OptionBtn>
            </div>
          </div>

          <!-- 消息体列表 -->
          <div :class="['message-box', 'chat-scroll']" ref="msgBox" id="message-box">
            <div class="mes-body">
              <div :class="[
                'mes-item',
                item.sender == userId ? 'mes-right' : 'mes-left',
              ]" v-for="item in messages" :key="item.id">
                <template v-if="item.action == '1'">
                  <img :src="item.sender == userId ? avatar : (checkFriend.avatar ? checkFriend.avatar : defaultAvatar)"
                    class="headpic" />
                  <div class="mes-cont">
                    <div class="mes-time">{{ formtMessageTime(item.timestamp) }}</div>
                    <div class="mes-info" :style="item.format == 1 ? '' : 'background-color: #fff;'">
                      <div v-if="item.format == 1">
                        {{ item.content }}
                      </div>
                      <div v-else-if="item.format == 2">
                        <img style="width: 100px" :src="parseFileUrl(item.content)" class="mes-img" />
                      </div>
                      <div v-else-if="item.format == 3">
                        <img style="width: 100px" :src="parseFileUrl(item.content)" class="mes-img" />
                      </div>
                      <div v-else-if="item.format == 4">
                        <audio controls="controls" height="100" width="200">
                          <source :src="parseFileUrl(item.content)" />
                        </audio>
                      </div>
                      <div v-else-if="item.format == 5">
                        <video controls="controls" width="200" height="200">
                          <source :src="parseFileUrl(item.content)" />
                        </video>
                      </div>
                      <div v-else-if="item.format == 6" class="mes-file">
                        <div class="mes-file-left">
                          <a @click="downloadFile(item)">
                            <div style="color:#333333; font-size: 16px; margin-bottom: 5px;">{{
                              parseContent(item.content).fileName
                            }}</div>
                            <div style="color:#999999; font-size: 14px;">{{ parseContent(item.content).size }}
                            </div>
                          </a>
                        </div>
                        <div class="mes-file-right">
                          <template
                            v-if="parseContent(item.content).type == 'xls' || parseContent(item.content).type == 'xlsx'">
                            <svg-icon icon-class="excel-file" style="font-size: 48px;" />
                          </template>
                          <template
                            v-else-if="parseContent(item.content).type == 'doc' || parseContent(item.content).type == 'docx'">
                            <svg-icon icon-class="word-file" style="font-size: 48px;" />
                          </template>
                          <template v-else-if="parseContent(item.content).type == 'pdf'">
                            <svg-icon icon-class="pdf-file" style="font-size: 48px;" />
                          </template>
                          <template
                            v-else-if="parseContent(item.content).type == 'ppt' || parseContent(item.content).type == 'pptx'">
                            <svg-icon icon-class="ppt-file" style="font-size: 48px;" />
                          </template>
                          <template v-else-if="parseContent(item.content).type == 'txt'">
                            <svg-icon icon-class="txt-file" style="font-size: 48px;" />
                          </template>
                          <template
                            v-else-if="parseContent(item.content).type == 'zip' || parseContent(item.content).type == 'rar' || parseContent(item.content).type == 'gz'">
                            <svg-icon icon-class="zip-file" style="font-size: 48px;" />
                          </template>
                          <template v-else>
                            <svg-icon icon-class="unknow-file" style="font-size: 48px;" />
                          </template>
                        </div>
                      </div>
                      <div v-else-if="item.format == 7">
                        <a target="_blank" :href="baseURL + parseContent(item.content).fileUrl"
                          :download="parseContent(item.content).fileName">{{
                            parseContent(item.content).fileName
                          }}</a>
                      </div>
                      <div v-else>
                        <!-- 其它开放下载 -->
                        <a target="_blank" :href="baseURL + parseContent(item.content).fileUrl"
                          :download="parseContent(item.content).fileName">{{
                            parseContent(item.content).fileName
                          }}</a>
                      </div>
                    </div>
                  </div>
                </template>
                <template v-if="item.action == '2'">
                  <div class="mes-tip">
                    <span v-if="item.sender == userId">{{ item.content }}</span>
                    <span v-else>{{ item.extra }}</span>
                  </div>
                </template>
              </div>
            </div>
            <div class="mes-loading" v-if="loadingShow"><i class="el-icon-loading"></i></div>
            <div class="mes-scroll"></div>
          </div>
          <!-- 输入区 -->
          <div class="input-area">
            <TEmoji v-if="emojiShow" @chooseEmoji="chooseEmoji" v-clickOutside="changeEmoji"></TEmoji>
            <div class="upload">
              <svg-icon icon-class="smile" class="icon" @click="changeEmoji" />
              <!-- 上传 -->
              <el-upload class="upload-demo" ref="uploadRef" :action="baseURL + uploadApi" :show-file-list="false"
                name="file" :data="{
                  pathName: 'im/',
                }" :limit="1" :on-success="uploadSuccess">
                <svg-icon icon-class="upload" class="icon" />
              </el-upload>
            </div>
            <div ref="msgBody" class="sub-input" contenteditable="plaintext-only" @keydown="handleKeydown"></div>
            <div class="sub-btn">
              <svg-icon icon-class="send" class="icon" @click="msgSend" />
            </div>
            <div class="message-tips" v-show="false">
              <audio controls="controls" height="100" width="200" ref="messageAudio" muted="muted" autoplay>
                <source src="" />
              </audio>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import TEmoji from "./emoji.vue";
import OptionBtn from "./optionBtn.vue";
import { onConnect, onbindAccount, onStop, sendRequest, ACTION_999 } from "./websocket/cim.web.sdk";
import { parseTime } from "@/utils/common";
import { download } from "@/utils/request";
import {
  listContactUser,
  listChat,
  getChat,
  saveChat,
  removeChat,
  listMessage,
  sendMessage,
  readMessage,
  cancelMessage,
} from "./websocket/axios";
export default {
  name: "ChartRoom",
  components: {
    TEmoji,
    OptionBtn,
  },
  data() {
    return {
      baseURL: process.env.VUE_APP_BASE_API,
      uploadApi: "/common/file/upload",
      defaultAvatar: require('@/assets/images/profile.jpg'),
      total: 0,
      current: 1,
      size: 20,
      show: false,
      emojiShow: false,
      mouseSelect: false,
      canSearch: false,
      frinedSearchKey: "",
      checkFriend: {},
      friends: [],
      userList: [],
      allUserList: [],
      messages: [],
      //展示的未读消息数量
      unreadCount: 0,
      messageRadioUrl: undefined,
      loadingShow: false
    };
  },
  computed: {
    userId() {
      return this.$store.getters.userId;
    },
    name() {
      return this.$store.getters.name;
    },
    avatar() {
      return this.$store.getters.avatar;
    },
  },
  created() {
    this.initConnect();
    window.onMessageReceived = this.onMessageReceived;
    window.onReplyReceived = this.onReplyReceived;
    window.onConnectFinished = this.onConnectFinished;
  },
  mounted() {
    this.checkFriend = {};
    this.listContactUser();
    this.listChat();
    this.$refs.msgBox.addEventListener("scroll", this.handleScroll);
  },
  beforeDestroy() {
    onStop();
  },
  methods: {
    // 获取联系人列表
    listContactUser() {
      listContactUser().then((res) => {
        this.allUserList = this.userList = res.data;
      });
    },
    // 获取聊天列表
    listChat() {
      listChat({ sender: this.userId }).then((res) => {
        if (res.data.length === 0) {
          this.friends = res.data;
          return;
        }
        this.friends = res.data;
        if (!this.show) {
          this.unreadCount = this._.sumBy(this.friends, 'unread');
          if (this.unreadCount > 0) {
            this.$refs.messageAudio.src = require('@/assets/common/unread-message.mp3');
            this.$refs.messageAudio.play();
            this.$notify({
              title: '消息',
              message: `您有${this.unreadCount}条未读消息，请及时查看`
            });
          }
          return;
        }
        if (this.checkFriend.id) {
          return;
        }
        this.checkFriend = res.data[0];
        this.changeFrind(this.checkFriend);
      });
    },
    // 获取指定会话的聊天内容
    listMessage(autoScroll) {
      this.loadingShow = true;
      listMessage({
        sender: this.userId,
        receiver: this.checkFriend.receiver,
        current: this.current,
        size: this.size,
      }).then((res) => {
        let newsMessages = [];
        // 如果是第一次就直接赋值，否则需要在原数组上拼接新数据
        if (this.current == 1) {
          newsMessages = res.data.records;
        } else {
          newsMessages = res.data.records.concat(this.messages);
        }
        this.total = parseInt(res.data.total) || 0;
        this.messages = newsMessages;
        if (autoScroll) {
          return;
        }
        this.scrollTo();
      });
    },
    // 展开会话
    showCall() {
      if (this.show) {
        this.show = false;
      } else {
        this.unreadCount = 0;
        this.show = true;
        this.listChat();
      }
    },
    // 关闭聊天界面
    close() {
      this.show = false;
    },
    // 显示联系人
    showSearch() {
      this.canSearch = true;
      this.$nextTick(() => {
        this.$refs.friendSearchInput.focus();
      });
    },
    // 搜索区域失去焦点关闭
    searchBlur() {
      if (this.mouseSelect) {
        return;
      }
      this.canSearch = false;
    },
    // 搜索过滤
    filterFrineds() {
      if (!this.frinedSearchKey) {
        this.userList = this.allUserList;
        return;
      }
      this.userList = this.allUserList.filter((e) => {
        return e.name.indexOf(this.frinedSearchKey) !== -1;
      });
    },
    //选择此联系人
    chooseToTalk(item) {
      //查找当前联系人在不在列表中
      let i = this._.findIndex(this.friends, { receiver: item.uid });
      if (i === -1) {
        //新增联系人
        saveChat({
          receiver: item.uid,
        }).then((res) => {
          this.checkFriend = res.data;
          this.checkFriend.avatar ? this.checkFriend.avatar : this.defaultAvatar;
          this.friends.unshift(this.checkFriend);
          this.messages = [];
          this.canSearch = false;
          this.send("2", "1", `您已经添加了${item.name}，现在可以聊天了`, `${this.name}添加了您，现在可以聊天了`);
        });
      } else {
        let obj = this.friends[i];
        this.checkFriend = { ...obj };
        this.canSearch = false;
        this.unshiftArrayByIndex(this.friends, i);
      }
    },
    // 选择聊天
    changeFrind(item) {
      this.checkFriend = {
        ...item,
      };
      item.unread = 0;
      this.current = 1;
      this.listMessage();
      getChat(item.id + '').then(res => {
        this.checkFriend.isOnline = res.data.isOnline;
        let i = this._.findIndex(this.friends, { receiver: this.checkFriend.receiver });
        if (i === -1) {
          return;
        }
        let friend = this.friends[i];
        friend.isOnline = res.data.isOnline;
      })
    },
    //选择表情包
    chooseEmoji(emoji) {
      this.emojiShow = false;
      this.$refs.msgBody.innerHTML += emoji;
      this.$refs.msgBody.focus();
      document.execCommand("selectAll", false, null);
      document.getSelection().collapseToEnd();
    },
    // 选择表情
    changeEmoji(e) {
      e.stopPropagation();
      this.emojiShow = !this.emojiShow;
    },
    // 上传文件
    uploadSuccess(res) {
      if (res.code == 200) {
        this.send("1", "6", JSON.stringify(res.data));
      } else {
        this.$message.error('文件上传失败，原因：' + res.msg);
      }
      this.$refs.uploadRef.clearFiles();
    },
    // div框按下按键
    handleKeydown(event) {
      // enter直接发送消息
      if (event.keyCode === 13) {
        this.msgSend();
        event.preventDefault(); // 阻止浏览器默认换行操作
        return false;
      }
      this.$refs.msgBody.focus();
    },
    // 发送消息
    msgSend() {
      let text = this.$refs.msgBody.innerHTML.replaceAll("&nbsp;", "").trim();
      if (!text || !this.checkFriend) {
        return;
      }
      this.send("1", "1", text);
      let i = this._.findIndex(this.friends, {
        receiver: this.checkFriend.receiver,
      });
      if (i === 0) {
        return;
      }
      this.unshiftArrayByIndex(this.friends, i);
    },
    // 消息发送 format 1
    // action 动作 1：聊天；2：添加好友；
    // format 聊天内容类型 1：文字；2：表情；3：图片；4：语音；5：视频；6：文件；7、链接 
    send(action = "", format = "", msg = "", extra = "") {
      if (!this.checkFriend.receiver) {
        this.$message({
          message: '请先添加好友！',
          type: 'warning'
        });
        return;
      }
      if (!action && !format) {
        return;
      }
      sendMessage({
        action,
        sender: this.userId,
        receiver: this.checkFriend.receiver,
        extra,
        content: msg,
        format,
      }).then((res) => {
        // 相当于好友添加成功以后
        //发送成功以后 删除消息内容 滚动到指定位置
        this.$refs.msgBody.innerHTML = "";
        this.messages.push(res.data);
        this.updateLastMessage(this.checkFriend.receiver, action, format, msg, extra);
        this.scrollTo();
      });
    },
    // 更新好友列表最近聊天内容
    updateLastMessage(receiver, action, format, msg, extra) {
      let i = this._.findIndex(this.friends, { receiver: receiver });
      if (i === -1) {
        //不在当前会话列表内 重新获取会话列表
        this.listChat();
        this.updateLastMessage(receiver, action, format, msg);
        return;
      }
      let friend = this.friends[i];
      let lastMessage;
      if (action == 2) {
        friend.lastMessage = receiver == this.userId ? extra : msg;
        friend.lastMessageTime = parseTime(new Date(), '{h}:{i}');
        return;
      }
      friend.lastMessage = this.formatMsg(format, msg);
      friend.lastMessageTime = parseTime(new Date(), '{h}:{i}');
    },
    /**
     * 格式化内容
     */
    formatMsg(format, msg) {
      let lastMessage = msg;
      if (format == 1) {
        lastMessage = msg;
      } else if (format == 2) {
        lastMessage = "[表情]";
      } else if (format == 3) {
        lastMessage = "[图片]";
      } else if (format == 4) {
        lastMessage = "[语音]";
      } else if (format == 5) {
        lastMessage = "[视频]";
      } else if (format == 6) {
        lastMessage = "[文件]";
      } else {
        lastMessage = "[其他]";
      }
      return lastMessage;
    },
    // 初始化websocket链接
    initConnect() {
      onConnect();
    },
    // 连接成功
    onConnectFinished() {
      onbindAccount(this.userId + "");
    },
    // 上线成功
    onReplyReceived(reply) {
      if (reply.key === "client_bind" && reply.code == 200) {
        console.log("上线响应");
      }
    },
    // 发送消息
    sendWebsocketMessage(message) {
      sendRequest(message);
    },
    // 收到消息
    onMessageReceived(message) {
      if (message.action === ACTION_999) {
        // 账号在其他设备登陆
        return false;
      }
      this.msgHanlder(message);
    },
    // 处理接收到的消息
    msgHanlder(msg) {
      // 处理提示信息
      if (!this.show) {
        let message = msg.content;
        if (msg.action == 1) {
          message = msg.content;
        } else if (msg.action == 2) {
          message = msg.sender == this.userId ? msg.content : msg.extra
        } else {
          message = msg.content;
        }
        this.$notify({
          title: msg.title,
          message: this.formatMsg(msg.format, message)
        });
        this.unreadCount++;
        this.messageRadioUrl = this.newMessageUrl;
        this.$refs.messageAudio.src = require('@/assets/common/new-message.mp3');
        this.$refs.messageAudio.play();
        return
      }
      // 如果是当前聊天对象发送消息
      if (msg.sender == this.checkFriend.receiver) {
        this.messages.push(msg);
        this.updateLastMessage(this.checkFriend.receiver, msg.action, msg.format, msg.content, msg.extra);
        readMessage(this.checkFriend.chatNumber, this.userId);
        this.scrollTo();
        return;
      }
      //如果再当前会话列表内 将对应会话人加在第一个，并且展示未读信息
      let i = this._.findIndex(this.friends, { receiver: msg.sender });
      if (i === -1) {
        //不在当前会话列表内 重新获取会话列表
        this.listChat();
      } else {
        let friend = this.friends[i];
        friend.unread++;
        this.updateLastMessage(msg.sender, msg.action, msg.format, msg.content, msg.extra)
        this.unshiftArrayByIndex(this.friends, i);
      }
    },
    // 格式化时间
    formtMessageTime(timestamp) {
      return parseTime(new Date(parseInt(timestamp)), '{y}/{m}/{d} {h}:{i}');
    },
    // 滑动到聊天底部
    scrollTo() {
      this.$nextTick(function () {
        this.loadImg();
        var msgBox = this.$refs.msgBox;
        msgBox.scrollTo({
          //滚动动画
          top: msgBox.scrollHeight,
          behavior: "instant",
        });
        this.current = 1;
        this.messages = this.messages.slice(-this.size);
        if (msgBox.scrollTop == 0) {
          this.loadingShow = false;
        }
      });
    },
    // 加载图片
    loadImg() {
      // 图片加载 complete代表文档加载完成
      if (document.readyState === "complete") {
        // 获取所有聊天图片dom
        let images = document.getElementsByClassName("mes-img");
        // 这里的images一定是要<img />的dom哦
        const promises = Array.prototype.slice
          .call(images)
          .map((node) => {
            return new Promise((resolve, reject) => {
              let loadImg = new Image();
              loadImg.src = node.src;
              loadImg.onload = () => {
                resolve(node);
              };
            });
          });
        // 解决图片在加载中滚动条滚动不到底部的问题
        Promise.all(promises).then((results) => {
          var dom = document.getElementById("message-box");
          dom.scrollTop = dom.scrollHeight;
        });
      }
    },
    // 判断文件路径
    parseContent(jsonStr) {
      let fileInfo = JSON.parse(jsonStr);
      return fileInfo;
    },
    // 判断文件路径
    parseFileUrl(jsonStr) {
      let fileInfo = this.parseContent(jsonStr);
      if (fileInfo.fileUrl.indexOf("http://") != -1 || fileInfo.fileUrl.indexOf("https://") != -1) {
        return fileInfo.fileUrl;
      }
      return this.baseURL + fileInfo.fileUrl;
    },
    //工具，根据index 将指定元素置顶
    unshiftArrayByIndex(arr, index) {
      let obj = arr.splice(index, 1)[0];
      arr.unshift(obj);
    },
    // 监听实现上拉滚动加载方法
    handleScroll() {
      //这里使用个延时加载，不然滑动屏幕的时候会不断触发方法，去计算高度，浪费性能
      let that = this
      clearTimeout(this.timer)
      that.timer = setTimeout(function () {
        let current = that.current;
        let msgBox = that.$refs.msgBox;
        // 获取当前页面高度
        let scrollTop = msgBox.scrollTop;
        let offsetTop = msgBox.offsetTop;
        if (scrollTop != 0) {
          return;
        }
        if (that.messages.length == that.total) {
          that.loadingShow = false;
          return;
        }
        current++
        that.current = current;
        that.listMessage(true);
        msgBox.scrollTo({
          top: offsetTop,
          behavior: 'instant'
        })
      }, 500);
    },
    // 下载文件
    downloadFile(item) {
      let fileInfo = this.parseContent(item.content);
      download(this.baseURL + fileInfo.fileUrl, '', fileInfo.fileName);
    }
  },
};
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>